package com.flame.shapeville.component.task2;

import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.*;
import lombok.Getter;

/**
 * Represents an angle visualization component used in Task 2.
 * <p>
 * This class draws a customizable angle with directional arrows and an indicator arc or right-angle marker.
 *
 * @author Flame Dev Team
 * @version 1.0
 * @since 2025-05-13
 */
public class Angle extends Pane {

    /**
     * The total size (width/height) of the drawing area.
     */
    private double size;

    /**
     * X-coordinate center of the angle.
     */
    private double centerX;

    /**
     * Y-coordinate center of the angle.
     */
    private double centerY;

    /**
     * The angle value in degrees, defining how wide the angle is drawn.
     */
    private double angle;

    /**
     * Constructs a new Angle instance.
     *
     * @param size the width and height of the drawing area
     * @param angle the angle value in degrees to be visualized
     */
    public Angle(double size, double angle) {
        this.size = size;
        this.angle = angle;
        this.setPrefWidth(size);
        this.setMaxWidth(size);
        this.setPrefHeight(size);
        this.setMaxHeight(size);
        centerX = size / 2;
        centerY = size / 2;
        draw();
    }

    /**
     * Draws the angle visualization based on current settings.
     * Includes two lines forming the angle, arrowheads, and an angle indicator.
     */
    private void draw() {
        Group group = new Group();

        Line line1 = createLine(0);
        Line line2 = createLine(angle);

        Polygon arrow1 = createArrow(line1.getEndX(), line1.getEndY(), centerX, centerY);
        Polygon arrow2 = createArrow(line2.getEndX(), line2.getEndY(), centerX, centerY);

        group.getChildren().addAll(line1, line2, arrow1, arrow2);

        Node angleIndicator = createAngleIndicator();
        group.getChildren().add(angleIndicator);

        this.getChildren().add(group);
    }

    /**
     * Creates a line representing one side of the angle.
     *
     * @param angle the angle in degrees from the horizontal axis
     * @return the Line object representing the arm of the angle
     */
    private Line createLine(double angle) {
        double rad = Math.toRadians(angle);
        return new Line(
                centerX, centerY,
                centerX + size * Math.cos(rad),
                centerY - size * Math.sin(rad)
        );
    }

    /**
     * Creates an arrowhead at the end of a line.
     *
     * @param x1 start X-coordinate of the line
     * @param y1 start Y-coordinate of the line
     * @param x2 end X-coordinate of the line
     * @param y2 end Y-coordinate of the line
     * @return a Polygon representing the arrowhead
     */
    private Polygon createArrow(double x1, double y1, double x2, double y2) {
        double arrowLength = 10;
        double arrowAngle = Math.atan2(y2 - y1, x2 - x1);

        double x3 = x1 + arrowLength * Math.cos(arrowAngle + Math.PI / 6);
        double y3 = y1 + arrowLength * Math.sin(arrowAngle + Math.PI / 6);
        double x4 = x1 + arrowLength * Math.cos(arrowAngle - Math.PI / 6);
        double y4 = y1 + arrowLength * Math.sin(arrowAngle - Math.PI / 6);

        Polygon arrow = new Polygon();
        arrow.getPoints().addAll(x1, y1, x3, y3, x4, y4);
        arrow.setFill(Color.BLACK);
        return arrow;
    }

    /**
     * Creates the angle indicator (arc for general angles, right-angle mark for 90°).
     *
     * @return a Node representing the angle indicator
     */
    private Node createAngleIndicator() {
        if (Math.abs(angle - 90) < 0.1) {
            Line perp1 = new Line(centerX + 15, centerY, centerX + 15, centerY - 15);
            Line perp2 = new Line(centerX + 15, centerY - 15, centerX, centerY - 15);
            perp1.setStroke(Color.BLUE);
            perp2.setStroke(Color.BLUE);
            return new Group(perp1, perp2);
        } else {
            Arc arc = new Arc(centerX, centerY, 20, 20, 0, angle);
            arc.setType(ArcType.OPEN);
            arc.setStroke(Color.BLUE);
            arc.setFill(null);
            return arc;
        }
    }

    /**
     * Redraws the angle visualization after updating the angle value.
     */
    private void redraw() {
        this.getChildren().clear();
        draw();
    }

    /**
     * Sets a new angle value and updates the visualization accordingly.
     *
     * @param angle the new angle value in degrees
     */
    public void setAngle(double angle) {
        this.angle = angle;
        redraw();
    }
}
